package pwd.allen.config;

import cn.hutool.db.Db;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.*;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;

/**
 * 数据库配置
 *
 * {@link org.springframework.transaction.annotation.Transactional}注解
 *  属性：
 *      propagation：指定事务传播机制，默认 Transaction
 *
 * @author lenovo
 * @create 2020-01-28 22:27
 **/
@EnableTransactionManagement//开启基于注解的声明式事务，可以代替xml的<tx:*>配置
@PropertySource(value = {"classpath:/db.properties"}, encoding = "UTF-8")
@Configuration
public class DBConfig {

    @Value("${jdbc.url}")
    private String jdbcUrl;
    @Value("${jdbc.driverName}")
    private String driverName;
    @Value("${jdbc.userName}")
    private String username;
    @Value("${jdbc.password}")
    private String password;

    /**
     * 提前初始化ValueResolver
     * 不加这个的话，配置类字段上的@Value没法正常注入配置文件的属性，因为在配置类初始化属性时 ValueResolver可能还没初始化
     * static不能去掉，否则初始化PropertySourcesPlaceholderConfigurer的时候会先初始化DBConfig，会有问题（代码：org.springframework.beans.factory.support.ConstructorResolver#instantiateUsingFactoryMethod(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])）
     * @return
     */
    @Bean
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }

    /**
     * @Value从配置文件中解析url
     * @see org.springframework.beans.factory.support.AbstractBeanFactory#resolveEmbeddedValue
     * @return
     * @throws Exception
     */
    @Bean(initMethod = "init")
    public DruidDataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        dataSource.setDriverClassName(driverName);
        dataSource.setUrl(jdbcUrl);
        dataSource.setLoginTimeout(5);
        return dataSource;
    }

    @Bean
    public PlatformTransactionManager dataSourceTransactionManager(DataSource dataSource) throws Exception {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean
    public JdbcTemplate jdbcTemplate(DataSource dataSource) throws Exception {
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        return jdbcTemplate;
    }
    /**
     * NamedParameterJdbcTemplate类是线程安全的
     * 该类的最佳使用方式不是每次操作的时候实例化一个新的NamedParameterJdbcTemplate，而是针对每个DataSource只配置一个NamedParameterJdbcTemplate实例
     */
    @Bean
    public NamedParameterJdbcTemplate namedParameterJdbcTemplate(JdbcTemplate jdbcTemplate) {
        return new NamedParameterJdbcTemplate(jdbcTemplate);
    }

}
